package org.xqh.study.operator;

import scala.Int;

/**
 * @ClassName JavaOperatorTest
 * @Description java运算符
 * @Author xuqianghui
 * @Date 2020/5/22 22:17
 * @Version 1.0
 */
public class JavaOperatorTest {

    /**
     * 按位与
     *
     * &按位与的运算规则是将两边的数转换为二进制位，然后运算最终值，运算规则即(两个为真才为真) 1&1=1 , 1&0=0 , 0&1=0 , 0&0=0
     *
     * 3的二进制位是0000 0011 ， 5的二进制位是0000 0101 ， 那么就是011 & 101，由按位与运算规则得知，001 & 101等于0000 0001，最终值为1
     *
     * 7的二进制位是0000 0111，那就是111 & 101等于101，也就是0000 0101，故值为5
     *
     * 负数:  负数 & 正数 为 正数,  负数 & 负数  为 负数.
     *  -3:  原码 0011 补码 1 1101
     *  -5:  原码 0101 补码 1 1011
     *                按位与: 1001 ==> 新补码  -1 --> 1000 取反 --> 0111 == -7
     *
     */
    public static void test1(){

        int x = 3 & 5;
        int y = 5 & 7;
        System.out.println("test1 x = "+x+", y = "+y);
    }

    /**
     * 逻辑运算符 &&  这个就不用说了
     */
    public static void test2(){

    }

    /**
     * | 按位或
     *
     * |按位或和&按位与计算方式都是转换二进制再计算，不同的是运算规则(一个为真即为真)1|0 = 1 , 1|1 = 1 , 0|0 = 0 , 0|1 = 1
     *
     * 6的二进制位0000 0110 , 2的二进制位0000 0010 , 110|010为110，最终值0000 0110，故6|2等于6
     */
    public static void test3(){

        /**
         * 6  0000 0110
         * 2  0000 0010
         *         0110 = 6
         */
        int x = 6 | 2;

        System.out.println("test3 x = "+x);
    }

    /**
     * 逻辑 或 ||
     */
    public static void test4(){

    }

    /**
     * 异或 运算符 ^
     * 符号为 XOR 或 ⊕（编程语言中常用 ^）
     *
     * ^异或运算符顾名思义，异就是不同，其运算规则为 1^0 = 1 , 1^1 = 0 , 0^1 = 1 , 0^0 = 0
     *
     * 5的二进制位是0000 0101 ， 9的二进制位是0000 1001，也就是0101 ^ 1001,结果为1100 , 00001100的十进制位是12
     */
    public static void test5(){

        /**
         * 5  0000 0101
         * 9  0000 1001
         *         1100 ==> 12
         */
        int x = 5 ^ 9;
        System.out.println("test5 x = "+x);
    }

    /**
     * 左移运算符 <<
     *
     * 5 << 2的意思为5的二进制位往左挪两位，
     * 右边补0，5的二进制位是0000 0101 ，
     * 就是把有效值101往左挪两位就是0001 0100 ，
     * 正数左边第一位补0，负数补1，等于乘于2的n次方，十进制位是20
     */
    public static void test6(){

        /**
         * 5:  0000 0101  左移两位 右边补0 ==> 0001 0100 就是 20
         */
        int x = 5 << 2;
        System.out.println("test6 x = "+x);
    }

    /**
     * 右移运算符  >>
     * 凡位运算符都是把值先转换成二进制再进行后续的处理，
     * 5的二进制位是0000 0101，右移两位就是把101左移后为0000 0001，
     * 正数左边第一位补0，负数补1，等于除于2的n次方，结果为1
     */
    public static void test7(){

        /**
         * 5: 0000 0101  右移两位   0000 0001 = 1
         */
        int x = 11 >> 2;

        System.out.println("test7 x = "+x);

    }

    /**
     * 取反运算符 ~
     *
     * !!!内存中存储的是 补码:
     *    9 内存中存储的是 0 1001
     *       9取反运算: 按位取反 得到新的 补码 1 0110 (负数) --> 计算新的原码
     *                 先减1 再按位(符号位不操作) 取反. 1 0101 --> 1 1010 = -10
     *    -9 内存中存储的是 1 0111  (原码各位取反+1)
     *       -9取反运算: 按位取反 --> 01000  得到新的 补码. 正数 补码 反码 原码 都是本身 所以 见过 是 8
     *
     * 符合公式   result = -(a + 1);
     *
     * 正数
     *   补码,反码都是其本身
     *   9的补码: 01001, 反码: 01001
     * 负数
     *   补码:  符号位不变, 其余各位求反, 末位+1     即 -1 的补码 为 11111
     *   反码:  符号位为1, 其余各位求反, 但末位不加1  即 -1 的反码为 11110
     * 也就是说 反码末位加1 就是补码
     *
     */
    public static void test8(){

        /**
         * 5:  0000 0101 取反后 ==> 1111 1010 加上 符号位 11111 1010
         * 负数的 补码 转 原码 为 先 减 1 (得到: 11111  1001)  然后 取反  10000 0110 = -6
         */
        int x = ~5;
        System.out.println("test8 x = "+x);
    }

    /**
     * 无符号右移运算符  >>>
     * 无符号右移运算符和右移运算符的主要区别在于负数的计算，
     * 因为无符号右移是高位补0，移多少位补多少个0。
     *
     * 15的二进制位是0000 1111 ， 右移2位0000 0011，结果为3
     *
     * !!!!!无符号 右移 负数情况:
     *          右移高位补0 , 然后直接计算  -5 >>> 2      0101
     *          -5的补码:  1111 1111 1111 1111 1111 1111 1111 1011
     *          右移两位:  0011 1111 1111 1111 1111 1111 1111 1110  =  1073741822
     *
     *          -5 >> 2
     *          高位补1    11111 1111 1111 1111 1111 1111 1111 1110
     *          减1取反    10000 0000 0000 0000 0000 0000 0000 0010 = -2
     *
     */
    public static void test9(){

        /**
         * 15:  0000 1111  >>> 2  =  0000 0011 = 3
         * -15: 在内存中存储的是 11111 0001  >>2 = 11111 1100 减 1 = 11111 1011 取反 得到 10000 0100 = -4
         *
         * -1 : 0000 0000 0000 0001  内存中存储的是 1111 1111 1111 1111 >>>2 = 0011 1111 1111 1111 减1 = 0011 1111 1111 1110 取反= 1100 0000 0000 0001
         *
         */
        int x = -15 >> 2;
        int y = -15 >>> 2;
        System.out.println("test9 x = "+x + ", y = "+y);
    }

    /**
     * 输出 二进制数据 (补码)
     */
    public static void test10(){
        int i = -15;
        // 11111111111111111111111111110001
        // 00111111111111111111111111111100
        System.out.println(Integer.toBinaryString(i));
        System.out.println(Integer.toBinaryString(i >>> 2));
        System.out.println(Integer.toBinaryString(-6 >>> 2));
        System.out.println(i >>> 2);

    }




    public static void main(String[] args) {
        /**
         * 0x44 = 68
         * 0xff = 255
         */
//        System.out.println(0x44 & 0xf3);
//        System.out.println(0x33 << 8);
//        System.out.println(Integer.toBinaryString(0x44));
//        System.out.println(Integer.toBinaryString(0xff));
//        /**
//         * 01000100
//         * 11111111
//         * 按位与 &
//         * 01000100 还是 68
//         */
//        System.out.println(-5 >>> 2);
//        System.out.println(-5 >> 2);
        /**
         * 连续五天登录 11111 = 0x1f
         */
//        System.out.println(0x1f & 0b100010011111);

//        System.out.println(2 ^ 2);
//        System.out.println(Long.toBinaryString(120L));
//        long a = 0b1111111L;
//        System.out.println(a);
        // 10101 01010
//        System.out.println(~11);
//        System.out.println(-5 << 3);
//        System.out.println(1 << 2);
//        System.out.println(-1 >>> 2);
//        System.out.println(-1 >>> 2);
//        System.out.println(-3 & -5);
//        System.out.println(Integer.toBinaryString(-5));
//        System.out.println(Integer.toBinaryString(-5).length());
        System.out.println(-3 ^ 5);
        System.out.println(-3 ^ -5);
        System.out.println(-10 >> 4);
        System.out.println(-10 / 16);
        System.out.println(10 >> 2);
        int a = 5;
        a &= -a;
        System.out.println(Integer.toBinaryString(a));
    }
}
